﻿/*****************************************介绍*****************************************
 * 作者：Ywh
 * 创建时间：2024-05-29 09:46:14
 * 功能：输入管理器
**************************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

namespace Game.Framework
{
    //[InternalModule(5)]
    public class InputManager : BaseManager<InputManager>, IModule
    {
        private Dictionary<string, InputInfo> m_InputDic = new Dictionary<string, InputInfo>();
        //当前遍历时取出的输入信息
        private InputInfo m_NowInputInfo;
        //是否开启了输入系统检测
        private bool m_IsStart;
        //用于在改建时获取输入信息的委托 只有当update中获取到信息的时候 再通过委托传递给外部
        private UnityAction<InputInfo> m_GetInputInfoCallBack;
        //是否开始检测输入信息
        private bool m_IsBeginCheckInput = false;

        private InputManager() { }

        /// <summary>
        /// 开启或者关闭我们的输入管理模块的检测
        /// </summary>
        /// <param name="isStart"></param>
        public void StartOrCloseInputMgr(bool isStart) => m_IsStart = isStart;

        /// <summary>
        /// 提供给外部改建或初始化的方法(键盘)
        /// </summary>
        /// <param name="key"></param>
        /// <param name="inputType"></param>
        public void ChangeKeyboardInfo(string eventType, KeyCode key, InputInfo.E_InputType inputType)
        {
            //初始化
            if (!m_InputDic.ContainsKey(eventType))
            {
                m_InputDic.Add(eventType, new InputInfo(inputType, key));
            }
            else//改建
            {
                //如果之前是鼠标 我们必须要修改它的按键类型
                m_InputDic[eventType].keyOrMouse = InputInfo.E_KeyOrMouse.Key;
                m_InputDic[eventType].key = key;
                m_InputDic[eventType].inputType = inputType;
            }
        }

        /// <summary>
        /// 提供给外部改建或初始化的方法(鼠标)
        /// </summary>
        /// <param name="eventType"></param>
        /// <param name="mouseID"></param>
        /// <param name="inputType"></param>
        public void ChangeMouseInfo(string eventType, int mouseID, InputInfo.E_InputType inputType)
        {
            //初始化
            if (!m_InputDic.ContainsKey(eventType))
            {
                m_InputDic.Add(eventType, new InputInfo(inputType, mouseID));
            }
            else//改建
            {
                //如果之前是鼠标 我们必须要修改它的按键类型
                m_InputDic[eventType].keyOrMouse = InputInfo.E_KeyOrMouse.Mouse;
                m_InputDic[eventType].mouseID = mouseID;
                m_InputDic[eventType].inputType = inputType;
            }
        }

        /// <summary>
        /// 移除指定行为的输入监听
        /// </summary>
        /// <param name="eventType"></param>
        public void RemoveInputInfo(string eventType)
        {
            if (m_InputDic.ContainsKey(eventType))
                m_InputDic.Remove(eventType);
        }

        /// <summary>
        /// 获取下一次的输入信息
        /// </summary>
        /// <param name="callBack"></param>
        public void GetInputInfo(UnityAction<InputInfo> callBack)
        {
            m_GetInputInfoCallBack = callBack;
            CommonMono.Instance.StartCoroutine(BeginCheckInput());
        }

        private IEnumerator BeginCheckInput()
        {
            //等一帧
            yield return 0;
            //一帧后才会被置成true
            m_IsBeginCheckInput = true;
        }

        private void Update()
        {
            //当委托不为空时 证明想要获取到输入的信息 传递给外部
            if (m_IsBeginCheckInput)
            {
                //当一个键按下时 然后遍历所有按键信息 得到是谁被按下了
                if (Input.anyKeyDown)
                {
                    InputInfo inputInfo = null;
                    //我们需要去遍历监听所有键位的按下 来得到对应输入的信息
                    //键盘
                    Array keyCodes = Enum.GetValues(typeof(KeyCode));
                    foreach (KeyCode inputKey in keyCodes)
                    {
                        //判断到底是谁被按下了 那么就可以得到对应的输入的键盘信息
                        if (Input.GetKeyDown(inputKey))
                        {
                            inputInfo = new InputInfo(InputInfo.E_InputType.Down, inputKey);
                            break;
                        }
                    }
                    //鼠标
                    for (int i = 0; i < 3; i++)
                    {
                        if (Input.GetMouseButtonDown(i))
                        {
                            inputInfo = new InputInfo(InputInfo.E_InputType.Down, i);
                            break;
                        }
                    }
                    //把获取到的信息传递给外部
                    m_GetInputInfoCallBack?.Invoke(inputInfo);
                    m_GetInputInfoCallBack = null;
                    //检测一次后就停止检测了
                    m_IsBeginCheckInput = false;
                }
            }

            //如果外部没有开启检测功能 就不要检测
            if (!m_IsStart)
                return;

            foreach (string eventType in m_InputDic.Keys)
            {
                m_NowInputInfo = m_InputDic[eventType];
                //键盘输入
                if (m_NowInputInfo.keyOrMouse == InputInfo.E_KeyOrMouse.Key)
                {
                    //是抬起还是按下还是长按
                    switch (m_NowInputInfo.inputType)
                    {
                        case InputInfo.E_InputType.Down:
                            if (Input.GetKeyDown(m_NowInputInfo.key))
                                EventCenter.Instance.Trigger(eventType);
                            break;
                        case InputInfo.E_InputType.Up:
                            if (Input.GetKeyUp(m_NowInputInfo.key))
                                EventCenter.Instance.Trigger(eventType);
                            break;
                        case InputInfo.E_InputType.Always:
                            if (Input.GetKey(m_NowInputInfo.key))
                                EventCenter.Instance.Trigger(eventType);
                            break;
                        default:
                            break;
                    }
                }
                //鼠标输入
                else
                {
                    switch (m_NowInputInfo.inputType)
                    {
                        case InputInfo.E_InputType.Down:
                            if (Input.GetMouseButtonDown(m_NowInputInfo.mouseID))
                                EventCenter.Instance.Trigger(eventType);
                            break;
                        case InputInfo.E_InputType.Up:
                            if (Input.GetMouseButtonUp(m_NowInputInfo.mouseID))
                                EventCenter.Instance.Trigger(eventType);
                            break;
                        case InputInfo.E_InputType.Always:
                            if (Input.GetMouseButton(m_NowInputInfo.mouseID))
                                EventCenter.Instance.Trigger(eventType);
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        private InitResult m_InitResult;

        void IModule.Init()
        {
            EventCenter.Instance.AddEventListen(EventName.MonoUpdate, Update);
            m_InitResult = new InitResult(E_ResultType.Success);
        }

        InitResult IModule.GetInitResult() => m_InitResult;

        void IModule.Clear()
        {
            EventCenter.Instance.RemoveEventListen(EventName.MonoUpdate, Update);
            m_InputDic.Clear();
            m_InputDic = null;
        }
    }

    /// <summary>
    /// 输入信息
    /// </summary>
    public class InputInfo
    {
        //具体输入的类型——键盘还是鼠标
        public E_KeyOrMouse keyOrMouse;
        //输入的类型——抬起、按下、长按
        public E_InputType inputType;
        //KeyCode
        public KeyCode key;
        //mouseID
        public int mouseID;

        /// <summary>
        /// 主要给键盘输入初始化
        /// </summary>
        /// <param name="inputType"></param>
        /// <param name="key"></param>
        public InputInfo(E_InputType inputType, KeyCode key)
        {
            keyOrMouse = E_KeyOrMouse.Key;
            this.inputType = inputType;
            this.key = key;
        }

        /// <summary>
        /// 主要给鼠标输入初始化
        /// </summary>
        /// <param name="inputType"></param>
        /// <param name="mouseID"></param>
        public InputInfo(E_InputType inputType, int mouseID)
        {
            keyOrMouse = E_KeyOrMouse.Mouse;
            this.inputType = inputType;
            this.mouseID = mouseID;
        }

        public enum E_KeyOrMouse
        {
            /// <summary>
            /// 键盘输入
            /// </summary>
            Key,
            /// <summary>
            /// 鼠标输入
            /// </summary>
            Mouse,
        }

        public enum E_InputType
        {
            /// <summary>
            /// 按下
            /// </summary>
            Down,
            /// <summary>
            /// 抬起
            /// </summary>
            Up,
            /// <summary>
            /// 长按
            /// </summary>
            Always,
        }
    }
}